package com.leyou.user.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.leyou.common.exception.LyException;
import com.leyou.common.utils.RegexUtils;
import com.leyou.user.dto.UserDTO;
import com.leyou.user.entity.User;
import com.leyou.user.mapper.UserMapper;
import com.leyou.user.service.UserService;
import org.apache.commons.lang.RandomStringUtils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.amqp.core.AmqpTemplate;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.TimeUnit;

import static com.leyou.common.constants.MQConstants.ExchangeConstants.*;
import static com.leyou.common.constants.MQConstants.RoutingKeyConstants.*;

@Service
public class UserServiceImpl extends ServiceImpl<UserMapper, User> implements UserService {
    @Autowired
    StringRedisTemplate redisTemplate;
    @Autowired
    AmqpTemplate amqpTemplate;
    @Autowired
    PasswordEncoder passwordEncoder;

    /*//构造函数注入
    private AmqpTemplate amqpTemplate;
    private RedisTemplate redisTemplate;
    public UserServiceImpl(StringRedisTemplate redisTemplate , AmqpTemplate amqpTemplate) {
        this.redisTemplate = redisTemplate;
        this.amqpTemplate = amqpTemplate;
    }*/


    @Override
    public Boolean checkDate(String data, Integer type) {
        String colName = null;
        switch (type){
            case 1:
                colName = "username";
                break;
            case 2:
                colName = "phone";
                if (!RegexUtils.isPhone(data)){
                    throw new LyException("手机号码有误", 400);
                }
                break;
            default:
                throw new LyException("查询参数有误", 400);
        }
        return query().eq(colName,data).count()==1; //唯一性
    }

    private final String KEY_PREFIX = "ly.user.verify:";
    @Override
    public void sendCode(String phone) {
        //1.验证手机号格式
        if (!RegexUtils.isPhone(phone)) {
            throw new LyException("请求参数",400);
        }
        Map<String, String> msg = new HashMap<>();
        msg.put("phone", phone);
        //2.使用Apach工具类生成6位数验证码
        String code = RandomStringUtils.randomNumeric(6);
        //3.保存验证码到Redis ，并设置了超时时间
        redisTemplate.opsForValue().set(KEY_PREFIX + phone ,code,5, TimeUnit.MINUTES);
        //4.发送rabbitMQ消息到ly-sms
        msg.put("code", code);
        amqpTemplate.convertAndSend(SMS_EXCHANGE_NAME,VERIFY_CODE_KEY,msg);

    }

    /**
     *  注册用户
     * @param user
     * @param code
     */
    @Override
    @Transactional
    public void register(User user, String code) {
        // 1.校验验证码
        // 1.1 取出redis中的验证码
        String cacheCode = redisTemplate.opsForValue().get(KEY_PREFIX + user.getPhone());
        // 1.2 比较验证码
        if (!StringUtils.equals(code, cacheCode)) {
            throw new LyException( "验证码错误",400);
        }
        // 2.对密码加密
        user.setPassword(passwordEncoder.encode(user.getPassword()));

        // 3.写入数据库
        save(user);
    }

    /**
     * 校验密码 TODO 有疑问？？？
     * @param username
     * @param password
     * @return
     */
    @Override
    public UserDTO queryUserByPhoneAndPassword(String username, String password) {
        //1.判断用户是否存在，不存在，直接抛出用户不存在； 注：getOne(条件)指定条件查询，并返回一条记录
        User user = getOne(new QueryWrapper<User>().eq("username", username));
        //2.判断 "悲观判断"先判断出错误，异常。
        if (user==null) {
            throw new LyException("用户名或密码错误",400);
        }
        //3.校验密码
        if (!passwordEncoder.matches(password,user.getPassword())) {
            //密码错误
            throw new LyException("用户名或密码错误", 400);
        }
        //4.转换DTO
        return new UserDTO(user);
    }

}
